<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Markdown 清洗工具（按首个 H1 过滤）</title>
  <style>
    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Noto Sans", "PingFang SC", "Microsoft YaHei", sans-serif; margin: 24px; line-height: 1.5; }
    h1 { font-size: 18px; margin: 0 0 12px; }
    .row { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
    .col { flex: 1 1 480px; min-width: 320px; }
    textarea { width: 100%; min-height: 320px; padding: 8px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; font-size: 13px; }
    .meta { margin: 12px 0; color: #444; }
    .btns { display: flex; gap: 12px; align-items: center; margin-top: 8px; }
    button { padding: 8px 14px; cursor: pointer; }
    .hint { color: #666; font-size: 12px; }
    .title { font-weight: 600; }
    .err { color: #b00020; }
  </style>
  <script>
    function findFirstH1(markdown) {
      const lines = markdown.split(/\r?\n/);
      const result = { title: null, titleLine: -1, content: "" };
      const stripTags = (html) => {
        const tmp = document.createElement('div');
        tmp.innerHTML = html;
        return (tmp.textContent || tmp.innerText || '').trim();
      };

      for (let i = 0; i < lines.length; i++) {
        const raw = lines[i];
        const s = raw.replace(/^\uFEFF/, '').trimStart();
        // Markdown H1: line starts with exactly "# " (not ##, ### ...)
        const mdMatch = s.match(/^#\s+(.+?)\s*$/);
        if (mdMatch && !s.startsWith('##')) {
          result.title = mdMatch[1].trim();
          result.titleLine = i;
          // Include H1 line itself in the output
          result.content = lines.slice(i).join("\n");
          return result;
        }
        // HTML <h1>...</h1>
        const htmlMatch = s.match(/^<h1(?:\s+[^>]*)?>([\s\S]*?)<\/h1>\s*$/i);
        if (htmlMatch) {
          result.title = stripTags(htmlMatch[1]);
          result.titleLine = i;
          // Include H1 line itself in the output
          result.content = lines.slice(i).join("\n");
          return result;
        }
      }
      // No H1 found
      result.content = markdown;
      return result;
    }

    function sanitizeFilename(name) {
      // Remove characters illegal on Windows and most filesystems
      let out = name.replace(/[\\/:*?"<>|]/g, ' ').trim();
      // Collapse whitespace to single dashes
      out = out.replace(/\s+/g, '-');
      // Limit length to something reasonable
      if (out.length > 120) out = out.slice(0, 120);
      if (!out) out = 'untitled';
      return out;
    }

    function update() {
      const src = document.getElementById('src');
      const out = document.getElementById('out');
      const h1El = document.getElementById('h1');
      const status = document.getElementById('status');
      const saveBtn = document.getElementById('save');

      const { title, titleLine, content } = findFirstH1(src.value || '');
      const filtered = stripTrailingTokensUsed(content || '');
      out.value = filtered;

      if (title && titleLine >= 0) {
        h1El.textContent = title;
        h1El.classList.remove('err');
        status.textContent = `已定位到首个 H1（第 ${titleLine + 1} 行）`;
        saveBtn.disabled = !filtered.trim();
      } else {
        h1El.textContent = '未找到 H1（将无法按标题命名）';
        h1El.classList.add('err');
        status.textContent = '提示：请确保存在形如 “# 标题” 的 H1 行，或 <h1>Title</h1>。';
        // 允许保存，但使用默认文件名
        saveBtn.disabled = !filtered.trim();
      }
    }

    function stripTrailingTokensUsed(text) {
      const lines = (text || '').split(/\r?\n/);
      // drop trailing blank lines
      while (lines.length && lines[lines.length - 1].trim() === '') {
        lines.pop();
      }
      if (lines.length) {
        const last = lines[lines.length - 1].trim();
        if (/tokens used:/i.test(last)) {
          lines.pop();
        }
      }
      return lines.join('\n');
    }

    function save() {
      const out = document.getElementById('out').value || '';
      const titleText = document.getElementById('h1').classList.contains('err')
        ? 'untitled' : document.getElementById('h1').textContent.trim();
      const filename = sanitizeFilename(titleText) + '.md';
      const blob = new Blob([out], { type: 'text/markdown;charset=utf-8' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    }

    document.addEventListener('DOMContentLoaded', () => {
      document.getElementById('src').addEventListener('input', update);
      document.getElementById('save').addEventListener('click', save);
      update();
    });
  </script>
  </head>
<body>
  <h1>Markdown 清洗工具</h1>
  <div class="meta"><span class="title">H1 标题：</span><span id="h1" class="err">未找到 H1（将无法按标题命名）</span></div>
  <div class="meta hint" id="status">提示：请粘贴/输入 Markdown，页面会自动截取首个 H1 下面的内容。</div>

  <div class="row">
    <div class="col">
      <div class="meta"><strong>输入 Markdown</strong></div>
      <textarea id="src" placeholder="# 我的标题\n\n这里是正文……"></textarea>
    </div>
    <div class="col">
      <div class="meta"><strong>过滤后内容（仅 H1 下方）</strong></div>
      <textarea id="out" readonly></textarea>
      <div class="btns">
        <button id="save" disabled>保存为 .md</button>
        <span class="hint">文件名将使用 H1 文本（若未找到则为 untitled.md）。</span>
      </div>
    </div>
  </div>
</body>
</html>
